#include "common.hpp"

static const char *optString = "r:i:h?";

static const struct option longOpts[] = {
	{ "help", no_argument, NULL, 'h' },
	{ "index", required_argument, NULL, 'i' },
	{ "resource", required_argument, NULL, 'r' },
	{ 0,0,0,0 }
};

int main (int argc, char* const argv[]) {
	srand( time(NULL) + getpid() );

	ipc::shared_memory_with_exceptions<size_t> vacias	( my_ftok(COUNTER|VACIAS));

	ipc::semaphore_with_exceptions mutex_vacias ( my_ftok(MUTEX|VACIAS),0);

//	ipc::semaphore_with_exceptions mutex_llenadora ( my_ftok(MUTEX|LLENADORA),MAX_LLENADORAS );
	ipc::semaphore_with_exceptions mutex_tapadora ( my_ftok(MUTEX|TAPADORA),0);

	ipc::messages_queue_with_exceptions llenadoras_salida ( my_ftok(MSG_QUEUE|LLENADORA) );

	int longIndex = 0;
	int option = 0;
	bool hay_botellas = false;
	bool ayuda = false;
	size_t procesadas = 0;
	long jugo = 0;
	int boca = -1;

	// Interpretación de parametros.
	while ( (option = getopt_long(argc,argv,optString,longOpts,&longIndex) ) != EOF ) {
		switch (option) {
			case '?':
			case 'h':
			case ':':
				ayuda = true;
				break;
			case 'i':
				boca = parse<size_t>(optarg,-1);
				if (boca >= MAX_LLENADORAS)
					boca = -1;
				break;
			case 'r':
				jugo = parse<long>(optarg,-1);
			default:
				break;
		}
	}

	if ( ayuda || boca < 0 || jugo < 0) {
		std::cerr << "Proceso de control de un brazo con bocas de llenado de jugo." << std::endl;
		std::cerr << "\tUso: " << argv[0] << " [-h] <-index natural> [-r natural]" << std::endl;
		std::cerr << "\tParametros:" << std::endl;
		std::cerr << "\t\t-h,--help:\tMostrar este mensaje de ayuda." << std::endl;
		std::cerr << "\t\t-i,--index:\tNúmero se semaforo a utilizar." << std::endl;
		std::cerr << "\t\t-r,--resource:\tNúmero de dosis de jugo disponibles en la estación." << std::endl;

		return (ayuda) ? 0 : -1;
	}

	// Recien en este momento se que boca de la llenadora utilizo.
	ipc::semaphore_with_exceptions mutex_llenadora (my_ftok(MUTEX|LLENADORA),boca);

	try {
		vacias.get(PERMITS);

		mutex_vacias.get(PERMITS);

		mutex_llenadora.get(PERMITS);
		mutex_tapadora.get(PERMITS);

		llenadoras_salida.get(PERMITS);

		sBotella llena;
		llena.tipo = SBOTELLA_TIPO;
		llena.estado = LLENA;

		logger << "Estación de llenado " << boca << ": Inicio." << nl;
		procesadas = 0;
		while (jugo > 0) {
			mutex_llenadora.wait();

			// Comprobar que existen botellas vacias.
			mutex_vacias.wait();
				hay_botellas = (*vacias) > 0;
				if (hay_botellas)
					(*vacias)--;
			mutex_vacias.signal();
		
			if (hay_botellas) {		
				jugo--;
				logger << "Estación de llenado " << boca << ": Llenando botella " << procesadas+1 << "." << nl;
				// llenar botella.
				usleep ( rand()%3000 + 1000 );

				// Enviar botella llena a la siguiente estación.
				procesadas++;
				logger << "Estación de llenado " << boca << ": Botella llenada " << procesadas << nl;

				llenadoras_salida.send(llena);

				// Solo libero la llenadora si aun quedaban botellas.
				mutex_llenadora.signal(boca);
			} else {
				logger << "Estación de llenado " << boca << ": detenida a la espera de botellas vacias." << nl;
			}
		} // while (jugo > 0)
		logger << "Estación de llenado " << boca << ": detenida por falta de jugo." << nl;

	} catch (ipc::exception& e) {
		logger << "Estación de llenado " << boca << ": " << e.what() << "." << nl;
		exit(-1);
	}
	logger << "Estación de llenado " << boca << ": Fin." << nl;
	return 0;
}
